package com.wuyan.wurpc.protocol;

import com.wuyan.wurpc.model.RpcRequest;
import com.wuyan.wurpc.model.RpcResponse;
import com.wuyan.wurpc.serializer.Serializer;
import com.wuyan.wurpc.serializer.SerializerFactory;
import io.vertx.core.buffer.Buffer;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.rmi.RemoteException;

/**
 * 协议消息解码器
 */
@Slf4j
public class ProtocolMessageDecoder {
    /**
     * 解码
     */
    public static ProtocolMessage<?> decode(Buffer buffer) throws IOException{
        //分别从指定位置读出Buffer
        log.info("开始解码 buffer：{}", buffer.toString());
        ProtocolMessage.Header header = new ProtocolMessage.Header();
        byte magic = buffer.getByte(0);
        //校验魔数
        if(magic != ProtocolConstant.PROTOCOL_MAGIC){
            throw new RuntimeException("消息magic 非法");
        }
        header.setMagic(magic);
        header.setVersion(buffer.getByte(1));
        header.setSerializer(buffer.getByte(2));
        header.setType(buffer.getByte(3));
        header.setStatus(buffer.getByte(4));
        header.setRequestId(buffer.getLong(5));
        header.setBodyLength(buffer.getInt(13));
        log.info("请求头header：{}", header);
        //解决粘包问题，只读指定长度的数据
        byte[] bodyBytes = buffer.getBytes(17, 17 + header.getBodyLength());
        //解析消息体
        log.info("开始解析消息体");
        ProtocolMessageSerializerEnum serializerEnum = ProtocolMessageSerializerEnum.getEnumByKey(header.getSerializer());
        if(serializerEnum == null){
            throw new RuntimeException("序列化消息的协议不存在");
        }
        Serializer serializer = SerializerFactory.getInstance(serializerEnum.getValue());
        log.info("消息解码serializer:{}", serializer);
        ProtocolMessageTypeEnum messageTypeEnum = ProtocolMessageTypeEnum.getEnumByKey(header.getType());
        if(messageTypeEnum == null){
            throw new RuntimeException("序列化消息的类型不存在");
        }
        switch (messageTypeEnum){
            case REQUEST:
                RpcRequest request = serializer.deserialize(bodyBytes, RpcRequest.class);
                log.info("解码REQUEST,request: {}", request);
                return new ProtocolMessage<>(header, request);
            case RESPONSE:
                RpcResponse response = serializer.deserialize(bodyBytes, RpcResponse.class);
                log.info("解码RESPONSE,response: {}", response);
                return new ProtocolMessage<>(header, response);
            case HEART_BEAT:
            case OTHERS:
            default:
                throw new RemoteException("暂不支持该消息类型");
        }
    }

}
